package com.suli.multimedia.component;


import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.suli.multimedia.entity.Message;
import com.suli.multimedia.util.MessageUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;


/**
 * @ ServerEndpoint 这个注解有什么作用？
 *
 * 这个注解用于标识作用在类上，它的主要功能是把当前类标识成一个WebSocket的服务端
 * 注解的值用户客户端连接访问的URL地址
 */
@Slf4j
@Component
@ServerEndpoint("/multimedia/{name}")
public class WebSocketServer {

    /**
     * 与某个客户端的连接对话，需要通过它来给指定的客户端发送消息，每个用户都要有且不一样，因此不能声明为static
     */
    private Session session;

    /**
     * 标识当前连接客户端的用户名
     */
    private String name;

    /**
     * 用于存所有的连接服务的客户端，这个对象存储是安全的
     */
    private static final ConcurrentHashMap<String, WebSocketServer> onlineUsers =
            new ConcurrentHashMap<>();

    /**
     * 连接建立是被调用
     * @param session 当前建立的会话
     * @param name url传参
     */
    @OnOpen
    public void OnOpen(Session session, @PathParam("name") String name) {
//将局部session赋值给全局的session
        this.session = session;
        //将前端请求路径的name取出
        this.name = name;
        //将登录的用户名进行记录，this是当前的WebSocketServer对象
        onlineUsers.put(name, this);
        //后台日志输出
        log.info(name+"：连接成功，当前连接人数为：{}", onlineUsers.size());
        //将当前登录的(所有)用户信息进行系统广播
        //1.将要发送的消息进行封装
        String message = MessageUtil.getMessage(true, null, onlineUsers.keySet());
        //2.消息推送
        sendMessageToAll(message);
    }


    /**
     * 发送信息给客户端
     * @param message 信息内容
     */
    private void sendMessageToAll(String message) {
        //将消息发送给所有的客户端
        //1.回去CurrenHashMap里面的key的Set集合（Set里面放的是用户名）
        // ConcurrentHashMap<String, WebSocketServer> onlineUsers; onlineUsers.put(name, this);
        Set<String> users=onlineUsers.keySet();
        //2.遍历key通过key获取ConcurrentHashMap里面保存的各个WebSocketServer对象(主要是获取里面的session)
        for (String user : users) {
            System.out.println(user);
            WebSocketServer webSocketServer = onlineUsers.get(user);
            try {
                //发送消息到客户端
                webSocketServer.session.getBasicRemote().sendText(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 连接关闭时调用
     * @ param session 当前会话
     * @ param closeReason 关闭原因
     */
    @OnClose
    public void OnClose() {
        onlineUsers.remove(this.name);
        String message = MessageUtil.getMessage(true, null, onlineUsers.keySet());
        sendMessageToAll(message);
        log.info(name+"：退出成功，当前连接人数为：{}", onlineUsers.size());
    }

    /**
     * 接收到客户端发送的数据时被调用
     * @param message 客户端发送过来的信息
     * @ param session 客户端会话
     */
    @OnMessage
    public void OnMessage(String message) {
        log.info("收到消息：{}", message);
        //根据用户名判断知道发送
        ObjectMapper mapper=new ObjectMapper();
        try {
            Message messageToOne = mapper.readValue(message, Message.class);

            if(messageToOne.getMessage().equals("ticketUSING")){
                String message1 = MessageUtil.getMessage(true, null, messageToOne.getMessage());
                sendToSomeOne(messageToOne.getToName(),message1);
            }else if(messageToOne.getMessage().equals("CANT|SCAN")){
                String message1 = MessageUtil.getMessage(true, null, messageToOne.getMessage());
                sendToSomeOne(messageToOne.getToName(),message1);
            }

        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }

    /**
     * 发送消息给指定的人
     * @param toName 发送的对象
     * @param message 消息内容
     */
    private void sendToSomeOne(String toName,String message){
        WebSocketServer webSocketServer = onlineUsers.get(toName);
        try {
            webSocketServer.session.getBasicRemote().sendText(message);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 连接错误是调用
     * @param session 当前会话
     * @param error 具体错误
     */
    @OnError
    public void OnError(Session session,Throwable error){
        error.printStackTrace();
    }

}